use cron::Schedule;
use darling::ast::NestedMeta;
use darling::{Error, FromMeta};
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn, ReturnType};


#[proc_macro_attribute]
pub fn scheduled(attr: TokenStream, item: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(item as ItemFn);
    let args = match NestedMeta::parse_meta_list(attr.into()) {
        Ok(v) => v,
        Err(e) => {
            let e: Error= e.into();
            return e.write_errors().into()
        },
    };
    let args = match ScheduledArgs::from_list(&args) {
        Ok(v) => v,
        Err(e) => return e.write_errors().into(),
    };
    println!("{:#?}", args);
    let rate = &args.rate;
    let cron = &args.cron;

    if rate.is_none() && cron.is_none() {
        return Error::custom("cron和rate不能都为空").write_errors().into()
    }

    if rate.is_some() && cron.is_some() {
        return Error::custom("cron和rate只能有一个属性有值").write_errors().into()
    }
    let func_block = &ast.block;
    let job_block = if cron.is_some() {
        let str_cron = cron.as_ref().unwrap().as_str();
        if Schedule::try_from(str_cron).is_err() {
            return Error::custom("cron表达式错误").write_errors().into()
        }
        quote! {
            let job = Job::new_async(#str_cron, move|_uuid,_lock|{
                Box::pin(async move{
                    #func_block
                })
            }).unwrap();
            sched.add(job).await.unwrap();
        }
    } else {
        let rate = rate.unwrap();
        if rate == 0 {
            return Error::custom("rate的值必须大于0").write_errors().into()
        }
        quote! {
            let job = Job::new_repeated_async(std::time::Duration::from_secs(#rate), move|_uuid,_lock|{
                Box::pin(async move{
                    #func_block
                })
            }).unwrap();
            sched.add(job).await.unwrap();
        }
    };
    let func_vis = &ast.vis;
    let func_decl = &ast.sig;
    let asyncness = func_decl.asyncness;
    if asyncness.is_none() {
        return Error::custom("必须是异步函数").write_errors().into()
    }
    let func_inputs = &func_decl.inputs;
    if !func_inputs.is_empty() {
        return Error::custom("函数不能有参数").write_errors().into()
    }
    let return_type = &func_decl.output;
    if let ReturnType::Type(_, _) = return_type {
        return Error::custom("函数不能有返回值").write_errors().into()
    }


    let task_start_block_header = quote! {
        let sched = JobScheduler::new().await.unwrap();
    };
    let task_start_block_tail = quote! {
        sched.start().await.unwrap();
    };
    quote! {
        #func_vis #func_decl{
            use scheduled_task::{Job, JobScheduler};
            #task_start_block_header
            #job_block
            #task_start_block_tail
        }
    }.into()
}


#[derive(Debug, FromMeta)]
struct ScheduledArgs {
    /// cron表达式
    cron: Option<String>,
    /// 间隔时间，单位：秒
    rate: Option<u64>,
}